package cn.tedu.submarine;

import javax.swing.JFrame;
import javax.swing.JPanel; //1
import java.awt.Graphics;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
 * 整个游戏世界
 */
public class World extends JPanel { //2
    //窗口的宽
    public static final int WIDTH = 641;
    //窗口的高
    public static final int HEIGHT = 479;

    //运行状态
    public static final int RUNNING = 0;
    //暂停状态
    public static final int PAUSE = 1;
    //游戏结束状态
    public static final int GAME_OVER = 2;
    private int state = RUNNING;//当前状态 默认为运行状态

    //如下这一堆对象为窗口中所显示的那堆对象
    private Battleship ship = new Battleship(); //战舰对象
    private SeaObject[] submarines = {};        //潜艇（侦察潜艇、鱼雷潜艇、水雷潜艇）数组对象
    private Mine[] mines = {};                  //水雷数组对象
    private Bomb[] bombs = {};                  //炸弹数组对象

    /**
     * 生成潜艇 侦察潜艇 鱼雷潜艇 水雷潜艇对象
     */
    private SeaObject nextSubmarine() {
        Random random = new Random();
        int type = random.nextInt(20); //生成0-19的随机整数
        if (type < 10) { //0-9 返回侦察潜艇对象
            return new ObserveSubmarine();
        } else if (type < 16) { //10-15返回鱼雷潜艇对象
            return new TorpedoSubmarine();
        } else {
            return new MineSubmarine();
        }
    }


    private int subEnterIndex = 0;//潜艇入场计数
    /**
     * 潜艇入场
     */
    private void submarineEnterAction() {//每10毫秒走一次
        subEnterIndex++;
        if (subEnterIndex % 40 == 0) {//每400（40*10）毫秒走一次
            SeaObject obj = nextSubmarine();
            submarines = Arrays.copyOf(submarines, submarines.length + 1);//给submarines数组扩容
            submarines[submarines.length - 1] = obj; //把obj放到数组最后一个元素上
        }
    }


    private int mineEnterIndex = 0;
    /**
     * 水雷入场
     */
    private void mineEnterAction() {//每10毫秒走一次
        mineEnterIndex++;//每10毫秒增1
        if (mineEnterIndex % 100 == 0) {//每1000毫秒走一次
            for (int i = 0; i < submarines.length; i++) {
                if (submarines[i] instanceof MineSubmarine) { //判断遍历的元素是否是水雷潜艇类型
                    MineSubmarine ms = (MineSubmarine) submarines[i]; //把潜艇强转为水雷潜艇
                    Mine mine = ms.shootMine();
                    mines = Arrays.copyOf(mines, mines.length + 1);
                    mines[mines.length - 1] = mine;
                }
            }

        }
    }

    /**
     * 海洋对象移动
     */
    private void moveAction() {//每10毫秒走一次
        for (int i = 0; i < submarines.length; i++) {
            submarines[i].move(); //潜艇移动
        }
        for (int i = 0; i < mines.length; i++) {
            mines[i].move();
        }
        for (int i = 0; i < bombs.length; i++) {
            bombs[i].move();
        }
    }

    /**
     * 删除越界或者死了的的海洋对象
     */
    private void outOfBoundsAction() { //每10毫秒走一次
        for (int i = 0; i < submarines.length; i++) {
            if (submarines[i].isOutOfBounds() || submarines[i].isDead()) { //若越界了 或者是DEAD状态的
                submarines[i] = submarines[submarines.length - 1]; //把越界的元素替换成最后一个元素
                submarines = Arrays.copyOf(submarines, submarines.length - 1);//缩容
            }
        }
        for (int i = 0; i < mines.length; i++) {
            if (mines[i].isOutOfBounds() || mines[i].isDead()) {
                mines[i] = mines[mines.length - 1];
                mines = Arrays.copyOf(mines, mines.length - 1);
            }
        }
        for (int i = 0; i < bombs.length; i++) {
            if (bombs[i].isOutOfBounds() || bombs[i].isDead()) {
                bombs[i] = bombs[bombs.length - 1];
                bombs = Arrays.copyOf(bombs, bombs.length - 1);
            }
        }
    }


    int score = 0;
    /**
     * 炸弹与潜艇的碰撞
     */
    private void bombBangAction() {
        for (int i = 0; i < bombs.length; i++) { //遍历所有炸弹
            Bomb b = bombs[i];     //获取每个炸弹
            for (int j = 0; j < submarines.length; j++) {  //遍历所有潜艇
                SeaObject s = submarines[j];  //获取每个潜艇
                if (b != null && s != null) {
                    if (b.isLive() && s.isLive() && s.isHit(b)) { //若都或者并且撞上了
                        b.goDead();//潜艇去死
                        s.goDead();//炸弹去死

                        if (s instanceof EnemyScore) {  //若潜艇为分
                            EnemyScore es = (EnemyScore) s; //将潜艇强转为分的接口
                            score += es.getScore(); //玩家得分
                        }
                        if (s instanceof EnemyLife) { //若潜艇为命
                            EnemyLife el = (EnemyLife) s; //将潜艇强转为命的接口
                            int num = el.getLife(); //获取命数
                            ship.addLife(num); //战舰增命
                        }
                    }
                }
            }
        }
    }


    /**
     * 水雷与战舰的碰撞
     */
    private void mineBangAction() { //每10毫秒走一次
        for (int i = 0; i < mines.length; i++) {
            Mine m = mines[i];
            if (m.isLive() && ship.isLive() && m.isHit(ship)) {
                m.goDead();
                ship.subtractLife();
            }
        }
    }

    /**
     * 检测游戏结束
     */
    private void checkGameOverAction() { //每10毫秒走一次
        if (ship.getLife() <= 0) { //若战舰命数<=0 表示游戏结束 则......
            state = GAME_OVER; //将当前状态修改为游戏结束状态
        }
    }


    /**
     * 启动程序的执行
     */
    public void action() {
        //键盘侦听器
        KeyAdapter k = new KeyAdapter() {
            /**重写keyReleased()按键抬起事件*/
            @Override
            public void keyPressed(KeyEvent e) {//按键按下时自动发生
                if (e.getKeyCode()==KeyEvent.VK_P){ //按下时p键
                    if (state == RUNNING){ //运行状态时 修改为暂停状态
                        state = PAUSE;
                    }else if (state == PAUSE){ //暂停状态时 修改为运行状态
                        state = RUNNING;
                    }
                }
                if (state == RUNNING){
                    if (e.getKeyCode() == KeyEvent.VK_SPACE) {//若按下的是空格键
                        Bomb bomb = ship.shootBomb(); //获取炸弹对象
                        bombs = Arrays.copyOf(bombs, bombs.length + 1); //扩容
                        bombs[bombs.length - 1] = bomb; //将bomb添加到bombs的最后一个元素上
                    }
                    if (e.getKeyCode() == KeyEvent.VK_LEFT) { //若按下的是左箭头
                        ship.moveLeft(); //战舰左移
                    }
                    if (e.getKeyCode() == KeyEvent.VK_RIGHT) { //若按下的是右箭头
                        ship.moveRight(); //战舰右移
                    }
                }
                System.out.println(mines.length);
            }
        };
        this.addKeyListener(k);//添加侦听器

        Timer timer = new Timer();//定时器对象
        int interval = 10;//定时间隔 毫秒为单位
        timer.schedule(new TimerTask() {
            @Override
            public void run() { //定时干的事 每10毫秒自动执行
                if (state == RUNNING){ //仅在运行状态时执行
                    submarineEnterAction(); //潜艇入场
                    mineEnterAction();      //水雷入场
                    moveAction();           //海洋对象移动
                    bombBangAction();       //炸弹与潜艇的碰撞
                    mineBangAction();       //水雷与战舰的碰撞
                    outOfBoundsAction();    //删除越界或者死了的的海洋对象
                    checkGameOverAction();  //检测游戏结束
                    repaint();  //重画，自动调用paint()方法
                }
            }
        }, interval, interval); //定时日程表
    }


    /**
     * 重写paint()画方法 g：画笔
     */
    public void paint(Graphics g) {
        Images.sea.paintIcon(null, g, 0, 0);//画海洋图
        ship.paintImage(g);//画战舰
        for (int i = 0; i < submarines.length; i++) {//遍历所有潜艇
            submarines[i].paintImage(g);//画潜艇
        }
        for (int i = 0; i < mines.length; i++) {//遍历所有水雷
            mines[i].paintImage(g);//画水雷
        }
        for (int i = 0; i < bombs.length; i++) {//遍历所有炸弹
            bombs[i].paintImage(g);//画炸弹
        }

        g.drawString("玩家得分:" + score, 120, 90); //画分
        g.drawString("剩余命数:" + ship.getLife(), 430, 90);

        //画游戏结束图
        if (state == GAME_OVER){
            Images.gameover.paintIcon(null, g, 0, 0);
        }

    }

    public static void main(String[] args) {
        //1)能点出来什么，看引用的类型
        //2)重写方法被调用时，看对象的类型

        JFrame frame = new JFrame(); //3
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH, HEIGHT + 39);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);

        world.action();//启动程序的执行
    }
}


















